package com.robertux.leaderboard.servlets;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.robertux.leaderboard.beans.EstadoEntidad;
import com.robertux.leaderboard.beans.JsonResponse;
import com.robertux.leaderboard.beans.RolUsuario;
import com.robertux.leaderboard.beans.TipoMeta;
import com.robertux.leaderboard.beans.entities.GrupoProducto;
import com.robertux.leaderboard.beans.entities.Meta;
import com.robertux.leaderboard.beans.entities.MetaProducto;
import com.robertux.leaderboard.beans.entities.Usuario;
import com.robertux.leaderboard.beans.entities.external.Sucursal;
import com.robertux.leaderboard.util.MethodExecutionSecurity;
import com.robertux.leaderboard.util.MethodParamsChecker;
import com.robertux.leaderboard.util.gestoresModelos.GestorEntidades;
import com.robertux.leaderboard.util.gestoresModelos.GestorEntidadesFarmacia;
import com.robertux.leaderboard.util.gestoresModelos.GestorGruposProductos;
import com.robertux.leaderboard.util.gestoresModelos.GestorMetas;
import com.robertux.leaderboard.util.gestoresModelos.GestorUsuarios;

@WebServlet("/MetasServlet/*")
public class MetasServlet extends BaseServlet {
	private static final long serialVersionUID = 1L;
	private Logger logger;
	private GestorMetas gestorMetas = new GestorMetas();
	private GestorUsuarios gestorUsr = new GestorUsuarios();
	private GestorGruposProductos gGprd = new GestorGruposProductos();
	private GestorEntidadesFarmacia gEntFrm = new GestorEntidadesFarmacia();
	private NumberFormat nFmt = new DecimalFormat("#.00");
       
    /**
     * @see BaseServlet#BaseServlet()
     */
    public MetasServlet() {
        super();
        this.logger = Logger.getLogger(this.getClass());
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"page", "rowsPerPage", "filter"})
    public JsonResponse getMetas(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray arr = new JsonArray();
    	List<Meta> metas;
    	long totalEvaluaciones = 0;
    	if(req.getParameter("branchId") != null) {
    		metas = this.gestorMetas.getMetas(Integer.parseInt(req.getParameter("branchId")), Integer.parseInt(req.getParameter("page")), Integer.parseInt(req.getParameter("rowsPerPage")), req.getParameter("filter"));
    		totalEvaluaciones = this.gestorMetas.getTotalMetas(Integer.parseInt(req.getParameter("branchId")), req.getParameter("filter"));
    	} else {
    		metas= this.gestorMetas.getMetas(Integer.parseInt(req.getParameter("page")), Integer.parseInt(req.getParameter("rowsPerPage")), req.getParameter("filter"));
    		totalEvaluaciones = this.gestorMetas.getTotalMetas(req.getParameter("filter"));
    	}
    	
    	
    	for(Meta meta: metas) {
    		JsonObject metaObj = new JsonObject();
    		Sucursal suc = gEntFrm.getSucursal(meta.getSucursalId());
    		metaObj.addProperty("metaId", meta.getId());
    		metaObj.addProperty("userId", meta.getUsuario().getId());
    		metaObj.addProperty("userName", meta.getUsuario().getUsuario());
    		metaObj.addProperty("userEmp", meta.getUsuario().getEmpleadoId());
    		metaObj.addProperty("empName", meta.getUsuario().getNombre());
    		metaObj.addProperty("name", meta.getNombre());
    		metaObj.addProperty("type", TipoMeta.fromCodigo(meta.getTipo()).getNombre());
    		metaObj.addProperty("products", meta.getMetaProductos().size() + " productos");
    		metaObj.addProperty("value", meta.getValor());
    		metaObj.addProperty("valueStr", meta.getTipo() == TipoMeta.POR_CANT_VENTAS.getCodigo()? meta.getValor() + " unidades": "$ " + nFmt.format(meta.getValor()));
    		metaObj.addProperty("frecuency", meta.getFrecuencia());
    		metaObj.addProperty("weight", meta.getPonderacion());
    		metaObj.addProperty("branch", suc != null? (suc.getId() + " - " + suc.getNombre()): "(ninguna)");
    		arr.add(metaObj);
    	}
    	
    	JsonResponse jsonResp = new JsonResponse(0, "OK", "metas", arr);
    	jsonResp.add("total", new JsonPrimitive(totalEvaluaciones));
    	return jsonResp;
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"userName"})
    public JsonResponse getMetasUsuario(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Usuario usr = null;
    	JsonArray arr = new JsonArray();
    	if((usr = this.gestorUsr.getUsuario(req.getParameter("userName"))) != null) {
	    	for(Meta meta: usr.getMetas()) {
	    		JsonObject metaObj = new JsonObject();
	    		Sucursal suc = gEntFrm.getSucursal(meta.getSucursalId());
	    		metaObj.addProperty("metaId", meta.getId());
	    		metaObj.addProperty("userId", meta.getUsuario().getId());
	    		metaObj.addProperty("userName", meta.getUsuario().getUsuario());
	    		metaObj.addProperty("userEmp", meta.getUsuario().getEmpleadoId());
	    		metaObj.addProperty("empName", meta.getUsuario().getNombre());
	    		metaObj.addProperty("name", meta.getNombre());
	    		metaObj.addProperty("type", TipoMeta.fromCodigo(meta.getTipo()).getNombre());
	    		metaObj.addProperty("products", meta.getMetaProductos().size() > 0? meta.getMetaProductos().get(0).getGrupoProducto().getNombre(): "(ninguno)");
	    		metaObj.addProperty("value", nFmt.format(meta.getValor()));
	    		metaObj.addProperty("frecuency", meta.getFrecuencia());
	    		metaObj.addProperty("weight", meta.getPonderacion());
	    		metaObj.addProperty("branch", suc != null? (suc.getId() + " - " + suc.getNombre()): "(ninguna)");
	    		arr.add(metaObj);
	    	}
    	} else {
    		return JsonResponse.fromError(1019, req.getParameter("userName"));
    	}
    	
    	return new JsonResponse(0, "OK", "metas", arr);
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"metaId"})
    public JsonResponse getMeta(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Meta meta = null;
    	JsonArray arr = new JsonArray();
    	if((meta = this.gestorMetas.getMeta(Integer.parseInt(req.getParameter("metaId")))) != null) {
    		JsonObject metaObj = new JsonObject();
    		metaObj.addProperty("metaId", meta.getId());
    		metaObj.addProperty("userId", meta.getUsuario().getId());
    		metaObj.addProperty("userName", meta.getUsuario().getUsuario() + " - " + meta.getUsuario().getNombre());
    		metaObj.addProperty("userEmp", meta.getUsuario().getEmpleadoId());
    		metaObj.addProperty("empName", meta.getUsuario().getNombre());
    		metaObj.addProperty("name", meta.getNombre());
    		metaObj.addProperty("type", meta.getTipo());
    		metaObj.addProperty("value", nFmt.format(meta.getValor()));
    		metaObj.addProperty("frecuency", meta.getFrecuencia());
    		metaObj.addProperty("weight", meta.getPonderacion());
    		metaObj.addProperty("branchId", meta.getSucursalId());
        	
    		Collections.sort(meta.getMetaProductos());
    		
    		for(GrupoProducto grp: new GestorGruposProductos().getGruposProductos()) {
    			int gPrdIndex = Collections.binarySearch(meta.getMetaProductos(), new MetaProducto(1, grp, null));
        		JsonObject grpObj = new JsonObject();
        		grpObj.addProperty("gPrdId", grp.getId());
        		grpObj.addProperty("name", grp.getNombre());
        		grpObj.addProperty("prdQty", grp.getDetalleGrupoProductos().size());
        		grpObj.addProperty("selected", (gPrdIndex >= 0));
        		arr.add(grpObj);
        	}
    		metaObj.add("productGroups", arr);
    		
    		return new JsonResponse(0, "OK", "meta", metaObj);
    	} else {
    		return JsonResponse.fromError(1025, req.getParameter("metaId"));
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"userName", "nombre", "tipo", "valor", "ponderacion", "gPrdIds", "addToAllInBranch", "branchId"})
    public JsonResponse addMeta(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Usuario usr = null;
    	
    	if(req.getParameter("addToAllInBranch").equals("true")) {
    		String branchId = null;
    		if((branchId = req.getParameter("branchId")) != null) {
    			boolean errorOccured = false;
    			for(Usuario brnUsr: this.gestorUsr.getUsuarios(Integer.parseInt(branchId))) {
    				Meta brnMeta = new Meta("MM", req.getParameter("nombre"), new BigDecimal(req.getParameter("ponderacion")), 
    						Integer.parseInt(branchId), Integer.parseInt(req.getParameter("tipo")), EstadoEntidad.ACTIVO.getCodigo(), new BigDecimal(req.getParameter("valor")));
    				
    				for(String prd: req.getParameter("gPrdIds").split(",")) {
	    				MetaProducto mPrd = new MetaProducto(1, gGprd.getGrupoProducto(Integer.parseInt(prd)), brnMeta);
	    				brnMeta.addMetaProducto(mPrd);
    				}
    				
    				brnUsr.addMeta(brnMeta);
    				if(!this.gestorUsr.actualizarUsuario(brnUsr)) {
    					errorOccured = true;
    				}
    			}
    			if(!errorOccured) {
    				return new JsonResponse(0, "Metas agregadas satisfactoriamente");
    			} else {
    				return JsonResponse.fromError(1024);
    			}
    		} else {
    			return JsonResponse.fromError(1005, "addMeta");
    		}
    	}
    	
    	if((usr = this.gestorUsr.getUsuario(req.getParameter("userName"))) != null) {
    		try {
				Meta meta = new Meta("MM", req.getParameter("nombre"), new BigDecimal(req.getParameter("ponderacion")), Integer.parseInt(req.getParameter("branchId")),
						Integer.parseInt(req.getParameter("tipo")), EstadoEntidad.ACTIVO.getCodigo(), new BigDecimal(req.getParameter("valor")));
				
				
				for(String prd: req.getParameter("gPrdIds").split(",")) {
    				MetaProducto mPrd = new MetaProducto(1, gGprd.getGrupoProducto(Integer.parseInt(prd)), meta);
    				meta.addMetaProducto(mPrd);
				}
				
				usr.addMeta(meta);
				if(this.gestorUsr.actualizarUsuario(usr)) {
					return new JsonResponse(0, "Meta agregada satisfactoriamente");
				} else {
					return JsonResponse.fromError(1024);
				}
			} catch (Exception e) {
				this.logger.error("Error tratando de parsear los par�metros de request del servlet: " + e.getMessage(), e);
				return JsonResponse.fromError(1024);
			}
    	} else {
    		return JsonResponse.fromError(1019, req.getParameter("userName"));
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"metaId", "nombre", "tipo", "valor", "ponderacion", "gPrdIds", "branchId"})
    public JsonResponse updateMeta(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Meta meta = null;
    	
    	if(req.getParameter("addToAllInBranch").equals("true")) {
    		this.logger.debug("addToAllInBranch");
    		String branchId = null;
    		if((branchId = req.getParameter("branchId")) != null) {
    			boolean errorOccured = false;
    			GestorEntidades<MetaProducto> gMProd = new GestorEntidades<MetaProducto>();
    			
    			for(Usuario brnUsr: this.gestorUsr.getUsuarios(Integer.parseInt(branchId))) {
    				this.logger.debug("\t--Recorriendo metas del usuario " + brnUsr.getUsuario());
    				Meta brnMeta = null;
    				
    				for(Meta metaUsr: brnUsr.getMetas()) {
    					if(metaUsr.getNombre().equals(req.getParameter("nombre"))) {
    						this.logger.debug("\t\t----Actualizando meta " + metaUsr);
    						brnMeta = metaUsr;
    						
    						brnMeta.setFrecuencia("MM");
    						brnMeta.setPonderacion(new BigDecimal(req.getParameter("ponderacion")));
    						brnMeta.setTipo(Integer.parseInt(req.getParameter("tipo")));
    						brnMeta.setValor(new BigDecimal(req.getParameter("valor")));
    						
    		    			for(MetaProducto mProd: brnMeta.getMetaProductos()) {
    		    				gMProd.eliminar(mProd);
    		    			}
    						brnMeta.getMetaProductos().clear();
    		    			this.gestorMetas.actualizarMeta(brnMeta);
    						
    						for(String prd: req.getParameter("gPrdIds").split(",")) {
        	    				MetaProducto mPrd = new MetaProducto(1, gGprd.getGrupoProducto(Integer.parseInt(prd)), brnMeta);
        	    				brnMeta.addMetaProducto(mPrd);
            				}
    						this.gestorMetas.actualizarMeta(brnMeta);
    						
    						break;
    					}
    				}
    				if(brnMeta == null) {
    					this.logger.debug("\t--El usuario " + brnUsr.getId() + " - " + brnUsr.getUsuario() + " no posee una meta con nombre " + req.getParameter("nombre") + ". Se creara una nueva");
    					brnMeta = new Meta("MM", req.getParameter("nombre"), new BigDecimal(req.getParameter("ponderacion")), 
    							Integer.parseInt(branchId), Integer.parseInt(req.getParameter("tipo")), EstadoEntidad.ACTIVO.getCodigo(), new BigDecimal(req.getParameter("valor")));
    					
    					for(String prd: req.getParameter("gPrdIds").split(",")) {
    	    				MetaProducto mPrd = new MetaProducto(1, gGprd.getGrupoProducto(Integer.parseInt(prd)), brnMeta);
    	    				brnMeta.addMetaProducto(mPrd);
        				}
        				
        				brnUsr.addMeta(brnMeta);
        				if(!this.gestorUsr.actualizarUsuario(brnUsr)) {
        					errorOccured = true;
        				}
    				}
    			}
    			if(!errorOccured) {
    				return new JsonResponse(0, "Metas actualizadas satisfactoriamente");
    			} else {
    				return JsonResponse.fromError(1024);
    			}
    		} else {
    			return JsonResponse.fromError(1005, "editMeta");
    		}
    	}
    	
    	if((meta = this.gestorMetas.getMeta(Integer.parseInt(req.getParameter("metaId")))) != null) {
    		try {
    			GestorEntidades<MetaProducto> gMProd = new GestorEntidades<MetaProducto>();
    			for(MetaProducto mProd: meta.getMetaProductos()) {
    				gMProd.eliminar(mProd);
    			}
    			
    			meta.getMetaProductos().clear();
    			this.gestorMetas.actualizarMeta(meta);
    			
    			for(String prd: req.getParameter("gPrdIds").split(",")) {
    				MetaProducto mPrd = new MetaProducto(1, gGprd.getGrupoProducto(Integer.parseInt(prd)), meta);
    				meta.addMetaProducto(mPrd);
				}
				meta.setNombre(req.getParameter("nombre"));
				meta.setTipo(Integer.parseInt(req.getParameter("tipo")));
				meta.setValor(new BigDecimal(req.getParameter("valor")));
				meta.setPonderacion(new BigDecimal(req.getParameter("ponderacion")));
				meta.setSucursalId(Integer.parseInt(req.getParameter("branchId")));
				if(this.gestorMetas.actualizarMeta(meta)) {
					return new JsonResponse(0, "Meta actualizada satisfactoriamente");
				} else {
					return JsonResponse.fromError(1026);
				}
			} catch (Exception e) {
				this.logger.error("Error tratando de actualizar la meta: " + e.getMessage(), e);
				return JsonResponse.fromError(1026);
			}
    	} else {
    		return JsonResponse.fromError(1025, req.getParameter("metaId"));
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"metaId"})
    public JsonResponse delMeta(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Meta meta = null;
    	if((meta = this.gestorMetas.getMeta(Integer.parseInt(req.getParameter("metaId")))) != null) {
    		meta.setEstado(EstadoEntidad.ELIMINADO.getCodigo());
    		if(this.gestorMetas.actualizarMeta(meta)) {
    			return new JsonResponse(0, "Meta eliminada satisfactoriamente");
    		} else {
    			return JsonResponse.fromError(1027);
    		}
    	} else {
    		return JsonResponse.fromError(1025, req.getParameter("metaId"));
    	}
    }

}
